home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / What's New? / Development Kits / Apple Game Sprockets DR1 / Examples / SoundSprocketTest / TS3Sound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-24  |  16.7 KB  |  708 lines  |  [TEXT/MPS ]

  1. /*
  2.  *    File:        TS3Sound.c
  3.  *    Author:        Dan Venolia
  4.  *
  5.  *    Contents:    Handles some of the sound stuff.
  6.  *
  7.  *    Copyright © 1996 Apple Computer, Inc.
  8.  */
  9.  
  10. #include <assert.h>
  11. #include <math.h>
  12. #include <stdio.h>
  13. #include <string.h>
  14.  
  15. #include <Controls.h>
  16. #include <Dialogs.h>
  17. #include <Sound.h>
  18. #include <Resources.h>
  19. #include <Timer.h>
  20.  
  21. #include "SoundSprocket.h"
  22.  
  23. #include "TS3Resource.h"
  24. #include "TS3Sound.h"
  25. #include "TS3Utils.h"
  26. #include "TS3Window.h"
  27.  
  28. static SndChannelPtr        gSoundChannel            = NULL;
  29. static SndListHandle        gSoundResource            = NULL;
  30. static DialogPtr            gSoundDialog            = NULL;
  31. static UserItemUPP            gSoundBoxUserItemProc    = NULL;
  32. static Snd3DInfo            gSoundPrev3DInfo;
  33.  
  34.  
  35. static WindowMethodPtr Sound_MetaHandler(
  36.     WindowMethod        inMethod);
  37.  
  38. static void Sound_ConsumeEvent(
  39.     WindowPtr            inWindow,
  40.     const EventRecord*    inEvent,
  41.     Boolean*            outConsumed);
  42.  
  43. static pascal void Sound_BoxUserItem(
  44.     DialogPtr            inDialog,
  45.     short                inItem);
  46.  
  47.  
  48. /* =============================================================================
  49.  *        Sound_Init (external)
  50.  *
  51.  *    Initializes the sound stuff.
  52.  * ========================================================================== */
  53. void Sound_Init(
  54.     void)
  55. {
  56.     SoundComponentLink            link;
  57.     
  58.     assert(kFeedbackItem_COUNT == kFeedbackItem_ExpectedCount);
  59.     
  60.     // Allocate the sound channel
  61.     SndNewChannel(&gSoundChannel, sampledSynth, initMono, NULL);
  62.     assert(gSoundChannel != NULL);
  63.     
  64.     // Install the 3D sound filters
  65.     link.description.componentType            = kSoundEffectsType;
  66.     link.description.componentSubType        = kSnd3DSubType;
  67.     link.description.componentManufacturer    = 'appl';
  68.     link.description.componentFlags            = 0;        
  69.     link.description.componentFlagsMask        = 0;    
  70.     link.mixerID                            = nil;
  71.     link.linkID                                = nil;
  72.     
  73.     SndSetInfo(gSoundChannel, siPreMixerSoundComponent, &link);
  74.  
  75.     // Set up the user item UPP
  76.     gSoundBoxUserItemProc = NewUserItemProc(Sound_BoxUserItem);
  77.     assert(gSoundBoxUserItemProc != NULL);
  78.     
  79.     // Grab the dialog
  80.     gSoundDialog = GetNewDialog(kDlogID_Feedback, NULL, (WindowPtr) -1);
  81.     assert(gSoundDialog != NULL);
  82.     
  83.     // Set up our method table
  84.     Window_New(gSoundDialog, Sound_MetaHandler);
  85.     
  86.     // Show the dialog
  87.     ShowWindow(gSoundDialog);
  88.     
  89.     // Initialize the Snd3DInfo state to garbage
  90.     memset(&gSoundPrev3DInfo, 0x55, sizeof(Snd3DInfo));
  91. }
  92.  
  93.  
  94. /* =============================================================================
  95.  *        Sound_Exit (external)
  96.  *
  97.  *    Prepares for exit.
  98.  * ========================================================================== */
  99. void Sound_Exit(
  100.     void)
  101. {
  102.     Sound_PlaySilence();
  103.     assert(gSoundResource == NULL);
  104.     
  105.     if (gSoundChannel != NULL)
  106.     {
  107.         SndDisposeChannel(gSoundChannel, true);
  108.         gSoundChannel = NULL;
  109.     }
  110.     
  111.     if (gSoundBoxUserItemProc != NULL)
  112.     {
  113.         DisposeRoutineDescriptor(gSoundBoxUserItemProc);
  114.         gSoundBoxUserItemProc = NULL;
  115.     }
  116.     
  117.     if (gSoundDialog != NULL)
  118.     {
  119.         DisposeDialog(gSoundDialog);
  120.         gSoundDialog = NULL;
  121.     }
  122. }
  123.  
  124.  
  125. /* =============================================================================
  126.  *        Sound_MetaHandler (internal)
  127.  *
  128.  *    Returns the method function pointer that corresponds to the given ID.
  129.  * ========================================================================== */
  130. WindowMethodPtr Sound_MetaHandler(
  131.     WindowMethod        inMethod)
  132. {
  133.     WindowMethodPtr        result;
  134.     
  135.     result = NULL;
  136.     
  137.     switch (inMethod)
  138.     {
  139.         case kWindowMethod_ConsumeEvent:
  140.             result = Sound_ConsumeEvent;
  141.         break;
  142.     }
  143.     
  144.     return result;
  145. }
  146.  
  147.  
  148. /* =============================================================================
  149.  *        Sound_ConsumeEvent (internal)
  150.  *
  151.  *    Called for each event when this is the front window.
  152.  * ========================================================================== */
  153. void Sound_ConsumeEvent(
  154.     WindowPtr            inWindow,
  155.     const EventRecord*    inEvent,
  156.     Boolean*            outConsumed)
  157. {
  158.     Boolean                consumed;
  159.     WindowPtr            window;
  160.     short                item;
  161.     
  162.     assert(inEvent != NULL);
  163.     assert(outConsumed != NULL);
  164.     
  165.     consumed = false;
  166.     
  167.     // Do dialog stuff
  168.     if (inEvent->what != keyDown || (inEvent->modifiers & cmdKey) == 0)
  169.     {
  170.         consumed = IsDialogEvent(inEvent);
  171.         if (consumed)
  172.         {
  173.             DialogSelect(inEvent, &window, &item);
  174.         }
  175.     }
  176.     
  177.     // Return the result
  178.     *outConsumed = consumed;
  179. }
  180.  
  181.  
  182. /* =============================================================================
  183.  *        Sound_PlaySilence (external)
  184.  *
  185.  *    Stops any sound that is playing.
  186.  * ========================================================================== */
  187. void Sound_PlaySilence(
  188.     void)
  189. {
  190.     SndCommand            sndCommand;
  191.     
  192.     sndCommand.cmd = quietCmd;
  193.     sndCommand.param1 = 0;
  194.     sndCommand.param2 = 0;
  195.     SndDoImmediate(gSoundChannel, &sndCommand);
  196.     
  197.     if (gSoundResource != NULL)
  198.     {
  199.         ReleaseResource((Handle) gSoundResource);
  200.         gSoundResource = NULL;
  201.     }
  202. }
  203.  
  204.  
  205. /* =============================================================================
  206.  *        Sound_PlayResource (external)
  207.  *
  208.  *    Plays the 'snd ' resource that has the given name.  Returns true if
  209.  *    successful; returns false if unsuccessful and therefore silence is happening.
  210.  * ========================================================================== */
  211. Boolean Sound_PlayResource(
  212.     Str255                inSndName)
  213. {
  214.     SndCommand            sndCommand;
  215.     long                offset;
  216.     
  217.     // Silence the sound channel and get rid of the old resource
  218.     Sound_PlaySilence();
  219.     
  220.     // Grab the resource
  221.     gSoundResource = (SndListHandle) GetNamedResource('snd ', inSndName);
  222.     if (gSoundResource == NULL || ResError() != noErr)
  223.     {
  224.         StopAlert(kAlrtID_BadSndLoad, NULL);
  225.         goto bail;
  226.     }
  227.     
  228.     // Lock it down
  229.     HLockHi((Handle) gSoundResource);
  230.     
  231.     // Play it indefinitely
  232.     GetSoundHeaderOffset(gSoundResource, &offset);
  233.     
  234.     sndCommand.cmd = soundCmd;
  235.     sndCommand.param1 = 0;
  236.     sndCommand.param2 = (long) *gSoundResource + offset;
  237.     SndDoImmediate(gSoundChannel, &sndCommand);
  238.  
  239.     sndCommand.cmd = freqCmd;
  240.     sndCommand.param1 = 0;
  241.     sndCommand.param2 = 60;
  242.     SndDoImmediate(gSoundChannel, &sndCommand);
  243.     
  244.     return true;
  245.  
  246.     // Error exit
  247. bail:
  248.     if (gSoundResource != NULL)
  249.     {
  250.         ReleaseResource((Handle) gSoundResource);
  251.         gSoundResource = NULL;
  252.     }
  253.     
  254.     return false;
  255. }
  256.  
  257.  
  258. /* =============================================================================
  259.  *        Sound_Set3DInfo (external)
  260.  *
  261.  *    Sends the given 3D info to the sound channel.
  262.  * ========================================================================== */
  263. void Sound_Set3DInfo(
  264.     const Snd3DInfo*    in3DInfo)
  265. {
  266.     Str255                str;
  267.     UnsignedWide        time;
  268.     
  269.     static UnsignedWide    prevTime = {0, 0};
  270.     
  271.     assert(in3DInfo != NULL);
  272.     
  273.     // Change the filter
  274.     SndSetInfo(gSoundChannel, si3DInfo, (Snd3DInfo*) in3DInfo);
  275.     //• CHECK ERROR
  276.     
  277.     // Update the dialog
  278.     Microseconds(&time);
  279.     
  280.     Utils_SetUInt32Field(
  281.         gSoundDialog,
  282.         kFeedbackItem_Updates,
  283.         1000000.0 / (time.lo-prevTime.lo),
  284.         true);
  285.     
  286.     prevTime = time;
  287.     
  288.     if (gSoundPrev3DInfo.cpuLoad != in3DInfo->cpuLoad)
  289.     {
  290.         Utils_SetUInt32Field(
  291.             gSoundDialog,
  292.             kFeedbackItem_CPULoad,
  293.             in3DInfo->cpuLoad,
  294.             true);
  295.         
  296.         gSoundPrev3DInfo.cpuLoad = in3DInfo->cpuLoad;
  297.     }
  298.     
  299.     if (gSoundPrev3DInfo.medium != in3DInfo->medium)
  300.     {
  301.         switch (in3DInfo->medium)
  302.         {
  303.             case kMediumAir:
  304.                 strcpy((char*) str, (char*) "\pkMediumAir");
  305.             break;
  306.             
  307.             case kMediumWater:
  308.                 strcpy((char*) str, (char*) "\pkMediumWater");
  309.             break;
  310.             
  311.             default:
  312.                 sprintf((char*) str, "x<<%lu>>", (unsigned long) in3DInfo->medium);
  313.                 str[0] = strlen((char*) str) - 1;
  314.         }
  315.         
  316.         Utils_SetStr255Field(
  317.             gSoundDialog,
  318.             kFeedbackItem_Medium,
  319.             str,
  320.             true);
  321.         
  322.         gSoundPrev3DInfo.medium = in3DInfo->medium;
  323.     }
  324.     
  325.     if (gSoundPrev3DInfo.humidity != in3DInfo->humidity)
  326.     {
  327.         Utils_SetFloatField(
  328.             gSoundDialog,
  329.             kFeedbackItem_Humidity,
  330.             in3DInfo->humidity,
  331.             true);
  332.         
  333.         gSoundPrev3DInfo.humidity = in3DInfo->humidity;
  334.     }
  335.     
  336.     if (gSoundPrev3DInfo.roomSize != in3DInfo->roomSize)
  337.     {
  338.         Utils_SetFloatField(
  339.             gSoundDialog,
  340.             kFeedbackItem_RoomSize,
  341.             in3DInfo->roomSize,
  342.             true);
  343.         
  344.         gSoundPrev3DInfo.roomSize = in3DInfo->roomSize;
  345.     }
  346.     
  347.     if (gSoundPrev3DInfo.roomReflectivity != in3DInfo->roomReflectivity)
  348.     {
  349.         Utils_SetFloatField(
  350.             gSoundDialog,
  351.             kFeedbackItem_RoomReflectivity,
  352.             in3DInfo->roomReflectivity,
  353.             true);
  354.         
  355.         gSoundPrev3DInfo.roomReflectivity = in3DInfo->roomReflectivity;
  356.     }
  357.     
  358.     if (gSoundPrev3DInfo.reverbAttenuation != in3DInfo->reverbAttenuation)
  359.     {
  360.         Utils_SetFloatField(
  361.             gSoundDialog,
  362.             kFeedbackItem_ReverbAttenuation,
  363.             in3DInfo->reverbAttenuation,
  364.             true);
  365.         
  366.         gSoundPrev3DInfo.reverbAttenuation = in3DInfo->reverbAttenuation;
  367.     }
  368.     
  369.     if (gSoundPrev3DInfo.sourceMode != in3DInfo->sourceMode)
  370.     {
  371.         switch (in3DInfo->sourceMode)
  372.         {
  373.             case kSourceModeLocalized:
  374.                 strcpy((char*) str, (char*) "\pkSourceModeLocalized");
  375.             break;
  376.             
  377.             case kSourceModeAmbient:
  378.                 strcpy((char*) str, (char*) "\pkSourceModeAmbient");
  379.             break;
  380.             
  381.             case kSourceModeBinaural:
  382.                 strcpy((char*) str, (char*) "\pkSourceModeBinaural");
  383.             break;
  384.             
  385.             default:
  386.                 sprintf((char*) str, "x<<%lu>>", (unsigned long) in3DInfo->sourceMode);
  387.                 str[0] = strlen((char*) str) - 1;
  388.         }
  389.         
  390.         Utils_SetStr255Field(
  391.             gSoundDialog,
  392.             kFeedbackItem_SourceMode,
  393.             str,
  394.             true);
  395.         
  396.         gSoundPrev3DInfo.sourceMode = in3DInfo->sourceMode;
  397.     }
  398.     
  399.     if (gSoundPrev3DInfo.referenceDistance != in3DInfo->referenceDistance)
  400.     {
  401.         Utils_SetFloatField(
  402.             gSoundDialog,
  403.             kFeedbackItem_ReferenceDistance,
  404.             in3DInfo->referenceDistance,
  405.             true);
  406.         
  407.         gSoundPrev3DInfo.referenceDistance = in3DInfo->referenceDistance;
  408.     }
  409.     
  410.     if (gSoundPrev3DInfo.coneAngleCos != in3DInfo->coneAngleCos)
  411.     {
  412.         Utils_SetFloatField(
  413.             gSoundDialog,
  414.             kFeedbackItem_ConeAngleCos,
  415.             in3DInfo->coneAngleCos,
  416.             true);
  417.         
  418.         gSoundPrev3DInfo.coneAngleCos = in3DInfo->coneAngleCos;
  419.     }
  420.     
  421.     if (gSoundPrev3DInfo.coneAttenuation != in3DInfo->coneAttenuation)
  422.     {
  423.         Utils_SetFloatField(
  424.             gSoundDialog,
  425.             kFeedbackItem_ConeAttenuation,
  426.             in3DInfo->coneAttenuation,
  427.             true);
  428.         
  429.         gSoundPrev3DInfo.coneAttenuation = in3DInfo->coneAttenuation;
  430.     }
  431.     
  432.     if (gSoundPrev3DInfo.currentLocation.longitude != in3DInfo->currentLocation.longitude)
  433.     {
  434.         Utils_SetFloatField(
  435.             gSoundDialog,
  436.             kFeedbackItem_Longitude,
  437.             in3DInfo->currentLocation.longitude,
  438.             true);
  439.         
  440.         gSoundPrev3DInfo.currentLocation.longitude = in3DInfo->currentLocation.longitude;
  441.     }
  442.     
  443.     if (gSoundPrev3DInfo.currentLocation.latitude != in3DInfo->currentLocation.latitude)
  444.     {
  445.         Utils_SetFloatField(
  446.             gSoundDialog,
  447.             kFeedbackItem_Latitude,
  448.             in3DInfo->currentLocation.latitude,
  449.             true);
  450.         
  451.         gSoundPrev3DInfo.currentLocation.latitude = in3DInfo->currentLocation.latitude;
  452.     }
  453.     
  454.     if (gSoundPrev3DInfo.currentLocation.distance != in3DInfo->currentLocation.distance)
  455.     {
  456.         Utils_SetFloatField(
  457.             gSoundDialog,
  458.             kFeedbackItem_Distance,
  459.             in3DInfo->currentLocation.distance,
  460.             true);
  461.         
  462.         gSoundPrev3DInfo.currentLocation.distance = in3DInfo->currentLocation.distance;
  463.     }
  464.     
  465.     if (gSoundPrev3DInfo.currentLocation.projectionAngle != in3DInfo->currentLocation.projectionAngle)
  466.     {
  467.         Utils_SetFloatField(
  468.             gSoundDialog,
  469.             kFeedbackItem_ProjectionAngle,
  470.             in3DInfo->currentLocation.projectionAngle,
  471.             true);
  472.         
  473.         gSoundPrev3DInfo.currentLocation.projectionAngle = in3DInfo->currentLocation.projectionAngle;
  474.     }
  475.     
  476.     if (gSoundPrev3DInfo.currentLocation.sourceVelocity != in3DInfo->currentLocation.sourceVelocity)
  477.     {
  478.         Utils_SetFloatField(
  479.             gSoundDialog,
  480.             kFeedbackItem_SourceVelocity,
  481.             in3DInfo->currentLocation.sourceVelocity,
  482.             true);
  483.         
  484.         gSoundPrev3DInfo.currentLocation.sourceVelocity = in3DInfo->currentLocation.sourceVelocity;
  485.     }
  486.     
  487.     if (gSoundPrev3DInfo.currentLocation.listenerVelocity != in3DInfo->currentLocation.listenerVelocity)
  488.     {
  489.         Utils_SetFloatField(
  490.             gSoundDialog,
  491.             kFeedbackItem_ListenerVelocity,
  492.             in3DInfo->currentLocation.listenerVelocity,
  493.             true);
  494.         
  495.         gSoundPrev3DInfo.currentLocation.listenerVelocity = in3DInfo->currentLocation.listenerVelocity;
  496.     }
  497.     
  498.     if (gSoundPrev3DInfo.reserved0 != in3DInfo->reserved0)
  499.     {
  500.         Utils_SetFloatField(
  501.             gSoundDialog,
  502.             kFeedbackItem_Reserved0,
  503.             in3DInfo->reserved0,
  504.             true);
  505.         
  506.         gSoundPrev3DInfo.reserved0 = in3DInfo->reserved0;
  507.     }
  508.     
  509.     if (gSoundPrev3DInfo.reserved1 != in3DInfo->reserved1)
  510.     {
  511.         Utils_SetFloatField(
  512.             gSoundDialog,
  513.             kFeedbackItem_Reserved1,
  514.             in3DInfo->reserved1,
  515.             true);
  516.         
  517.         gSoundPrev3DInfo.reserved1 = in3DInfo->reserved1;
  518.     }
  519.     
  520.     if (gSoundPrev3DInfo.reserved2 != in3DInfo->reserved2)
  521.     {
  522.         Utils_SetFloatField(
  523.             gSoundDialog,
  524.             kFeedbackItem_Reserved2,
  525.             in3DInfo->reserved2,
  526.             true);
  527.         
  528.         gSoundPrev3DInfo.reserved2 = in3DInfo->reserved2;
  529.     }
  530.     
  531.     if (gSoundPrev3DInfo.reserved3 != in3DInfo->reserved3)
  532.     {
  533.         Utils_SetFloatField(
  534.             gSoundDialog,
  535.             kFeedbackItem_Reserved3,
  536.             in3DInfo->reserved3,
  537.             true);
  538.         
  539.         gSoundPrev3DInfo.reserved3 = in3DInfo->reserved3;
  540.     }
  541.     
  542.     if (gSoundPrev3DInfo.virtualSourceCount != in3DInfo->virtualSourceCount)
  543.     {
  544.         Utils_SetFloatField(
  545.             gSoundDialog,
  546.             kFeedbackItem_VirtualSourceCount,
  547.             in3DInfo->virtualSourceCount,
  548.             true);
  549.         
  550.         gSoundPrev3DInfo.virtualSourceCount = in3DInfo->virtualSourceCount;
  551.     }
  552. }
  553.  
  554.  
  555. /* =============================================================================
  556.  *        Sound_Configure (external)
  557.  *
  558.  *    Presents the modal dialog to configure the 3D sound stuff.
  559.  * ========================================================================== */
  560. void Sound_Configure(
  561.     void)
  562. {
  563.     DialogPtr            dialog;
  564.     short                itemType;
  565.     Handle                itemHandle;
  566.     Rect                itemBounds;
  567.     ControlHandle        stereoControl;
  568.     ControlHandle        monoControl;
  569.     ControlHandle        headphonesControl;
  570.     ControlHandle        angleControl;
  571.     Snd3DSetup            snd3DInitialSetup;
  572.     Snd3DSetup            snd3DSetup;
  573.     Boolean                changed;
  574.     Boolean                ok;
  575.     short                item;
  576.     
  577.     // Grab the dialog
  578.     dialog = GetNewDialog(kDlogID_Config3DSound, NULL, (WindowPtr) -1);
  579.     assert(dialog != NULL);
  580.     
  581.     // Grab the control handles
  582.     GetDialogItem(dialog, kConfig3DSoundItem_Stereo, &itemType, &itemHandle, &itemBounds);
  583.     stereoControl = (ControlHandle) itemHandle;
  584.     
  585.     GetDialogItem(dialog, kConfig3DSoundItem_Mono, &itemType, &itemHandle, &itemBounds);
  586.     monoControl = (ControlHandle) itemHandle;
  587.     
  588.     GetDialogItem(dialog, kConfig3DSoundItem_Headphones, &itemType, &itemHandle, &itemBounds);
  589.     headphonesControl = (ControlHandle) itemHandle;
  590.     
  591.     GetDialogItem(dialog, kConfig3DSoundItem_Angle, &itemType, &itemHandle, &itemBounds);
  592.     angleControl = (ControlHandle) itemHandle;
  593.     
  594.     // Do the user items
  595.     GetDialogItem(dialog, kConfig3DSoundItem_SetupBox, &itemType, &itemHandle, &itemBounds);
  596.     SetDialogItem(dialog, kConfig3DSoundItem_SetupBox, itemType, (Handle) gSoundBoxUserItemProc, &itemBounds);
  597.     
  598.     GetDialogItem(dialog, kConfig3DSoundItem_AngleBox, &itemType, &itemHandle, &itemBounds);
  599.     SetDialogItem(dialog, kConfig3DSoundItem_AngleBox, itemType, (Handle) gSoundBoxUserItemProc, &itemBounds);
  600.     
  601.     GetDialogItem(dialog, kConfig3DSoundItem_OKHilite, &itemType, &itemHandle, &itemBounds);
  602.     SetDialogItem(dialog, kConfig3DSoundItem_OKHilite, itemType, (Handle) Utils_GetOKUserItemProc(), &itemBounds);
  603.     
  604.     // Get the initial state of the setup
  605.     SndGetInfo(gSoundChannel, si3DSetup, &snd3DSetup);
  606.     snd3DInitialSetup = snd3DSetup;
  607.     
  608.     // Process events
  609.     changed = true;
  610.     ok = true;
  611.     do
  612.     {
  613.         // Update the dialog
  614.         if (changed)
  615.         {
  616.             SetControlValue(stereoControl,        snd3DSetup.speakerKind == kSpeakerKindStereo);
  617.             SetControlValue(monoControl,        snd3DSetup.speakerKind == kSpeakerKindMono);
  618.             SetControlValue(headphonesControl,    snd3DSetup.speakerKind == kSpeakerKindHeadphones);
  619.             SetControlValue(angleControl,        snd3DSetup.speakerAngle * 180.0 / _PI);
  620.             
  621.             HiliteControl(angleControl, (snd3DSetup.speakerKind == kSpeakerKindStereo) ? 0 : 255);
  622.             
  623.             changed = false;
  624.         }
  625.         
  626.         // Grab the next dialog event
  627.         ModalDialog(NULL, &item);
  628.         
  629.         // Process the dialog item
  630.         switch (item)
  631.         {
  632.             case kConfig3DSoundItem_OK:
  633.                 ok = false;
  634.             break;
  635.             
  636.             case kConfig3DSoundItem_Cancel:
  637.                 snd3DSetup = snd3DInitialSetup;
  638.                 changed = true;
  639.                 ok = false;
  640.             break;
  641.             
  642.             case kConfig3DSoundItem_Stereo:
  643.                 snd3DSetup.speakerKind = kSpeakerKindStereo;
  644.                 changed = true;
  645.             break;
  646.             
  647.             case kConfig3DSoundItem_Mono:
  648.                 snd3DSetup.speakerKind = kSpeakerKindMono;
  649.                 changed = true;
  650.             break;
  651.             
  652.             case kConfig3DSoundItem_Headphones:
  653.                 snd3DSetup.speakerKind = kSpeakerKindHeadphones;
  654.                 changed = true;
  655.             break;
  656.             
  657.             case kConfig3DSoundItem_Angle:
  658.                 snd3DSetup.speakerAngle = GetControlValue(angleControl) * _PI / 180.0;
  659.                 changed = true;
  660.             break;
  661.         }
  662.         
  663.         // Update the sound channel
  664.         if (changed)
  665.         {
  666.             SndSetInfo(gSoundChannel, si3DSetup, &snd3DSetup);
  667.         }
  668.     }
  669.     while (ok);
  670.     
  671.     // Take down the dialog
  672.     DisposDialog(dialog);
  673. }
  674.  
  675.  
  676. /* =============================================================================
  677.  *        Sound_BoxUserItem (internal)
  678.  *
  679.  *    Draws the user item by framing it with a gray box.
  680.  * ========================================================================== */
  681. pascal void Sound_BoxUserItem(
  682.     DialogPtr            inDialog,
  683.     short                inItem)
  684. {
  685.     short                itemType;
  686.     Handle                itemHandle;
  687.     Rect                itemBounds;
  688.     RGBColor            color;
  689.     
  690.     GetDialogItem(inDialog, inItem, &itemType, &itemHandle, &itemBounds);
  691.     
  692.     color.red   =
  693.     color.green =
  694.     color.blue  = 0x7777;
  695.     
  696.     RGBForeColor(&color);
  697.     
  698.     FrameRect(&itemBounds);
  699.     
  700.     color.red   =
  701.     color.green =
  702.     color.blue  = 0x0000;
  703.     
  704.     RGBForeColor(&color);
  705. }
  706.  
  707.  
  708.